package gotnames.web.st;

import gotnames.Utils;
import gotnames.dm.KTrans;
import gotnames.dm.ProfilePicture;
import gotnames.dm.ProfilePictureData;
import gotnames.dm.QueryBuilder;
import gotnames.dm.User;
import gotnames.dm.User.Gender;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.jdo.PersistenceManager;

import org.apache.commons.io.IOUtils;

import com.medallia.spider.Task;
import com.medallia.tiny.CollUtils;
import com.medallia.tiny.Empty;
import com.medallia.tiny.Encoding;
import com.medallia.tiny.Func;
import com.medallia.tiny.Funcs;
import com.medallia.tiny.Strings;

/**
 * See {@link DownloadArchiveTask}.
 */
public class UploadArchiveTask extends Task {
	
	@Input interface Params {
		byte[] archive();
	}
	
	PostAction action(User user, final PersistenceManager pm, Params p) {
		if (!user.isAdmin())
			return redirectToTask(GuessNamesTask.class);
		
		final Long groupKey = user.getGroupKey();
		
		ZipInputStream zipFile = new ZipInputStream(new ByteArrayInputStream(p.archive()));
		ZipEntry ze;
		try {
			final List<String> msg = Empty.list();
			final Map<String, ProfilePictureData> profilePics = Empty.hashMap();
			List<String> rows = null;
 			while ((ze = zipFile.getNextEntry()) != null) {
				String fileName = ze.getName();
				if ("Users.csv".equals(fileName)) {
					rows = CollUtils.tail(Strings.split(IOUtils.toString(zipFile, Encoding.CHARSET_UTF8_NAME), "\n"));
				} else {
					// profile picture
					int lastDot = fileName.lastIndexOf('.');
					String fullName = lastDot < 0 ? fileName : fileName.substring(0, lastDot);
					try {
	 					final ProfilePictureData profilePicture = ProfilePictureData.getProfilePicture(IOUtils.toByteArray(zipFile));
						msg.add("Read profile picture for " + fileName);
						profilePics.put(fullName, profilePicture);
					} catch (RuntimeException e) {
						msg.add("Failed to read profile picture for " + fileName + ": " + e.getMessage());
					}
				}
			}
 			
 			if (rows == null)
 				return rawStringUtf8("No 'Users.csv' in zip file");
 			
 			List<User> users = Funcs.map(rows, new Func<String, User>() {
				@Override public User call(String row) {
	 				List<String> cells = Strings.split(row, "\t");
	 				final String firstName = notNull("First name", row, strip(cells.get(0)));
	 				final String lastName = notNull("Last name", row, strip(cells.get(1)));
	 				final String email = notNull("Email", row, strip(cells.get(2)));
	 				final Gender gender = notNull("Gender", row, Gender.parse(strip(cells.get(3))));
	 				
	 				final boolean disableEmail = cells.size() > 4 && Boolean.valueOf(strip(cells.get(4)).toLowerCase());
	 				final boolean admin = cells.size() > 5 && Boolean.valueOf(strip(cells.get(5)).toLowerCase());
	 				
	 				return new KTrans<User>(pm) {
						@Override protected User call() {
			 				User u = QueryBuilder.begin(pm, User.class).getSingleByField("email", email);
			 				if (u == null) {
			 					u = User.newUser(groupKey);
			 					u.setEmail(email);
			 				}
			 				u.setFirstName(firstName);
			 				u.setLastName(lastName);
			 				u.setGender(gender);
			 				u.setDisableEmail(disableEmail);
			 				u.setAdmin(admin);
			 				
			 				ProfilePictureData profilePicture = profilePics.get(u.getFullName());
			 				if (profilePicture != null)
			 					u.setProfilePictureInfo(profilePicture);
			 				
			 				pm.makePersistent(u);
			 				
							msg.add("User saved: " + u.getFullName());
			 				return u;
						}
	 				}.go();
				}
 			});
 			
 			for (User u : users) {
 				// Update profile picture if present
				ProfilePicture.saveProfilePicture(u, pm, profilePics.get(u.getFullName()));
 			}
			
			return rawStringUtf8("OK; updated " + rows.size() + " users\n\n" + Strings.join("\n", msg));
		} catch (IOException e) {
			return rawStringUtf8("Unable to read ZIP archive: " + e.getMessage());
		}
	}
	
	private <X> X notNull(String field, Object context, X x) {
		return Utils.notNull(x, field + " is required in " + context);
	}

	private String strip(String str) {
		return str.replace("\"", "");
	}

}
